// Package requests 处理请求数据和表单验证逻辑
package requests

import (
	"github.com/gin-gonic/gin"
	"github.com/thedevsaddam/govalidator"

	"github.com/runningwater/gohub/pkg/response"
)

// ValidatorFunc 定义验证函数类型
// 该函数接受一个数据和一个上下文参数，并返回一个包含错误信息的映射
type ValidatorFunc func(any, *gin.Context) map[string][]string

// Validate 函数用于验证请求数据
// 它接受一个上下文对象、要验证的数据和一个验证函数
// 如果验证成功，返回 true；否则返回 false，并在上下文中设置错误响应
// c: gin.Context 上下文对象
// obj: 需要验证的数据对象
// handler: 自定义验证函数
// 返回值是一个布尔值，表示验证是否成功  如果验证失败，返回错误信息，否则返回空映射
// 调用示例：
//
//	if ok := requests.Validate(c, &requests.SignupRequest{}, requests.Signup); !ok {
//	      return
//	}
func Validate(c *gin.Context, obj any, handler ValidatorFunc) bool {

	// 1. 解析请求, 支持 JSON 数据、表单请求和 URL Query 参数
	if err := c.ShouldBind(obj); err != nil {
		response.BadRequest(c, err, "请求解析错误，请确认请求格式是否正确。上传文件请使用 multipart 标头， 参数请使用 JSON 格式")
		// c.AbortWithStatusJSON(http.StatusUnprocessableEntity, gin.H{
		// 	"message": "请求解析错误，请确认请求格式是否正确。上传文件请使用 multipart 标头， 参数请使用 JSON 格式",
		// 	"error":   err.Error(),
		// })
		return false
	}

	// 2. 执行验证
	errs := handler(obj, c)

	// 3. 如果验证失败，返回错误信息
	if len(errs) > 0 {
		// c.AbortWithStatusJSON(http.StatusUnprocessableEntity, gin.H{
		// 	"message": "请求验证不通过，具体请查看 errors",
		// 	"errors":  errs,
		// })
		response.ValidationError(c, errs)
		return false
	}
	// 4. 返回验证成功
	return true
}

// validate 函数用于执行数据验证
//
//	它接受数据、验证规则和自定义错误信息，并返回验证结果
//	data: 需要验证的数据
//	rules: 验证规则
//	messages: 自定义错误信息
//	返回值是一个映射，包含字段名和对应的错误信息
func validate(data any, rules, messages govalidator.MapData) map[string][]string {

	opts := govalidator.Options{
		Data:          data,
		Rules:         rules,
		TagIdentifier: "valid", // 使用结构体中的valid标签
		Messages:      messages,
	}

	return govalidator.New(opts).ValidateStruct()
}

// validateFile 函数用于验证文件上传
//
//	它接受上下文对象、数据、验证规则和自定义错误信息，并返回验证结果
//	c: gin.Context 上下文对象
//	data: 需要验证的数据
//	rules: 验证规则
//	messages: 自定义错误信息
//	返回值是一个映射，包含字段名和对应的错误信息
func validateFile(c *gin.Context, data any, rules, messages govalidator.MapData) map[string][]string {
	opts := govalidator.Options{
		Request:       c.Request,
		Rules:         rules,
		TagIdentifier: "valid", // 使用结构体中的valid标签
		Messages:      messages,
	}

	return govalidator.New(opts).Validate()
}
